﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.Serialization;

namespace ERPStore.Models
{
	/// <summary>
	/// Panier de commande
	/// </summary>
	[Serializable]
	[DataContract]
	public class OrderCart : IModelIdentity
	{
		public OrderCart()
		{
			CreationDate = DateTime.Now;
			Items = new List<CartItem>();
			Code = Guid.NewGuid().ToString().Replace("-","").Substring(0,25);
			AcceptCondition = false;
			ShippingFee = new Fee();
			AcceptConversion = false;
			DiscountList = new List<IDiscount>();
		}

		/// <summary>
		/// Numéro interne du panier
		/// </summary>
		/// <value>The id.</value>
		[DataMember]
		public int Id { get; set; }
		/// <summary>
		/// Code du panier généralement un GUID
		/// </summary>
		/// <value>The code.</value>
		[DataMember]
		public string Code { get; set; }
		/// <summary>
		/// Date de création du panier
		/// </summary>
		/// <value>The creation date.</value>
		[DataMember]
		public DateTime CreationDate { get; set; }
		/// <summary>
		/// Identifiant interne du client s'il est identifié
		/// </summary>
		/// <value>The customer id.</value>
		[DataMember]
		public int? CustomerId { get; set; }
		/// <summary>
		/// Identitifiant du visiteur
		/// </summary>
		/// <value>The visitor id.</value>
		[DataMember]
		public string VisitorId { get; set; }
		/// <summary>
		/// Retourne le nombre d'item dans le panier
		/// </summary>
		/// <value>The item count.</value>
		[IgnoreDataMember]
		public int ItemCount
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Count();
			}
		}

		/// <summary>
		/// Liste des items du panier
		/// </summary>
		/// <value>The items.</value>
		[DataMember]
		public List<CartItem> Items { get; private set; }

		/// <summary>
		/// Dernière page affichée avant d'arriver sur la page du panier
		/// </summary>
		/// <value>The last page.</value>
		[DataMember]
		public string LastPage { get; set; }
		/// <summary>
		/// Message à ajouter à la commande par l'utilisateur
		/// </summary>
		/// <value>The message.</value>
		[DataMember]
		public string Message { get; set; }
		/// <summary>
		/// L'utlisateur peut ajouter un code à lui pour retrouver plus tard celui ci dans la commande
		/// </summary>
		/// <value>The customer document reference.</value>
		[DataMember]
		public string CustomerDocumentReference { get; set; }
		/// <summary>
		/// Indique qu'il s'agit du panier en cours
		/// </summary>
		/// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
		[DataMember]
		public bool IsActive { get; set; }
		/// <summary>
		/// Document de conversion (Commande ou Devis)
		/// </summary>
		/// <value>The converted entity id.</value>
		[DataMember]
		public int? ConvertedEntityId { get; set; }
		/// <summary>
		/// Date de conversion du panier
		/// </summary>
		/// <value>The conversion date.</value>
		[DataMember]
		public DateTime? ConversionDate { get; set; }

		/// <summary>
		/// Nom de la source etant à l'origine de la création du panier
		/// </summary>
		/// <value>The name of the lead source.</value>
		[DataMember]
		public string LeadSourceName { get; set; }

		/// <summary>
		/// Identifiant de la source de creéation du panier
		/// </summary>
		/// <value>The lead source id.</value>
		[DataMember]
		public string LeadSourceId { get; set; }

		/// <summary>
		/// Adresse de livraison du panier
		/// </summary>
		/// <value>The delivery address.</value>
		[DataMember]
		public Address DeliveryAddress { get; set; }
		/// <summary>
		/// Adresse de facturation du panier
		/// </summary>
		/// <value>The billing address.</value>
		[DataMember]
		public Address BillingAddress { get; set; }
		/// <summary>
		/// Mode de reglement selectionné pour la commande
		/// </summary>
		/// <value>The payment mode.</value>
		[DataMember]
		public string PaymentModeName { get; set; } 
		/// <summary>
		/// L'utilisateur accepte les conditions générales de vente
		/// </summary>
		/// <value><c>true</c> if [accept condition]; otherwise, <c>false</c>.</value>
		[DataMember]
		public bool AcceptCondition { get; set; }
		/// <summary>
		/// Accepte les livraisons partielles sur la commande
		/// </summary>
		/// <value>
		/// 	<c>true</c> if [allow partial delivery]; otherwise, <c>false</c>.
		/// </value>
		[DataMember]
		public bool AllowPartialDelivery { get; set; }
		/// <summary>
		/// Ce panier est un cadeau
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is present; otherwise, <c>false</c>.
		/// </value>
		[DataMember]
		public bool IsPresent { get; set; }

		#region Totals

		[DataMember]
		public decimal GrossTotal
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.CatalogTotal);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant total HT du panier sans l'eco participation
		/// </summary>
		/// <value>The total.</value>
		[DataMember]
		public decimal Total
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.Total);
			}
			set
			{
				// Serialization
			}
		}

		[DataMember]
		public decimal ItemsDiscountTotal 
		{
			get
			{
				return GrossTotal - Total;
			}
			set
			{
				// for serialization
			}
		}

		/// <summary>
		/// Montant total du panier hors recyclage, port et produits remisés
		/// </summary>
		public decimal TotalWithoutDiscountByItem
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Where(i => i.Product.SelectedOffer == null).Sum(i => i.Total);
			}
		}

		/// <summary>
		/// Montant total Remisé
		/// </summary>
		public decimal TotalWithDiscount
		{
			get
			{
				return Math.Max(GrossTotal - DiscountTotal - ItemsDiscountTotal, 0);
			}
		}

		/// <summary>
		/// Montant de la tva du panier sans l'eco participation
		/// </summary>
		/// <value>The total tax.</value>
		[DataMember]
		public decimal TotalTax
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.TotalTax);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant total TTC du panier sans l'eco participation
		/// </summary>
		/// <value>The total with tax.</value>
		[DataMember]
		public decimal TotalWithTax
		{
			get
			{
				long sum = Convert.ToInt64(Math.Round(this.Total * 100m));
				sum += Convert.ToInt64(Math.Round(this.TotalTax * 100m));

				return sum / 100m;
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant total ht de l'eco participation
		/// </summary>
		/// <value>The recycle total.</value>
		[DataMember]
		public decimal RecycleTotal
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.RecycleTotal);
			}
			set
			{
				// For serialization
			}
		}
		/// <summary>
		/// Montant total de la tva de l'eco participation
		/// </summary>
		/// <value>The recycle tax total.</value>
		[DataMember]
		public decimal RecycleTaxTotal
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.RecycleTaxTotal);
			}
			set
			{
				// For serialization
			}
		}
		/// <summary>
		/// Montant total ttc de l'eco participation
		/// </summary>
		/// <value>The recycle total with tax.</value>
		[DataMember]
		public decimal RecycleTotalWithTax
		{
			get
			{
				if (Items == null)
				{
					return 0;
				}
				return Items.Sum(i => i.RecycleTotalWithTax);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Remise totale sur le panier
		/// </summary>
		[DataMember]
		public decimal DiscountTotal
		{
			get
			{
				return DiscountList.Sum(i => i.Discount);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Taxe totale sur la remise totale
		/// </summary>
		[DataMember]
		public decimal DiscountTaxTotal
		{
			get
			{
				return DiscountList.Sum(i => i.DiscountWithTax - i.Discount);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Remise totale avec taxe
		/// </summary>
		[DataMember]
		public decimal DiscountWithTaxTotal
		{
			get
			{
				return DiscountList.Sum(i => i.DiscountWithTax);
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant total ht du panier y compris l'eco participation
		/// </summary>
		/// <value>The grand total.</value>
		[DataMember]
		public decimal GrandTotal
		{
			get
			{
				return Total + RecycleTotal - DiscountTotal + ShippingFee.Total;
			}
			set
			{
				// For serialization
			}
		}
		/// <summary>
		/// Montant total de la tva y compris avec l'eco participation
		/// </summary>
		/// <value>The grand tax total.</value>
		[DataMember]
		public decimal GrandTaxTotal
		{
			get
			{
				return TotalTax + RecycleTaxTotal - DiscountTaxTotal + ShippingFee.TotalTax;
			}
			set
			{
				// For serialization
			}
		}
		/// <summary>
		/// Montant total ttc du panier y compris avec l'eco participation
		/// </summary>
		/// <value>The grand total with tax.</value>
		[DataMember]
		public decimal GrandTotalWithTax
		{
			get
			{
				return TotalWithTax + RecycleTotalWithTax - DiscountWithTaxTotal + ShippingFeeTotalWithTax;
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant total du port de livraison TTC
		/// </summary>
		/// <value>The shipping fee total with tax.</value>
		[DataMember]
		public decimal ShippingFeeTotalWithTax
		{
			get
			{
				return ShippingFee.TotalWithTax;
			}
			set
			{
				// For serialization
			}
		}

		/// <summary>
		/// Montant de la remise globale en pourcentage
		/// </summary>
		/// <value>The discount.</value>
		[DataMember]
		public double Discount
		{
			get
			{
				if (Total == 0)
				{
					return 0;
				}
				return Convert.ToDouble(DiscountTotal / Total);
			}
			set
			{
				// For serialization
			}
		}

		#endregion

		/// <summary>
		/// Frais de livraison
		/// </summary>
		/// <value>The shipping fee.</value>
		[DataMember]
		public Fee ShippingFee { get; set; }

		/// <summary>
		/// Frais de port verouillé par le créateur du panier
		/// </summary>
		/// <value><c>true</c> if [shipping fee locked]; otherwise, <c>false</c>.</value>
		[DataMember]
		public bool ShippingFeeLocked { get; set; }

		/// <summary>
		/// Liste des coupons de réduction associé au panier
		/// </summary>
		public IEnumerable<IDiscount> DiscountList { get; set; }

		/// <summary>
		/// Montant à atteindre pour obtenir un franco de port
		/// </summary>
		/// <value>The free of shipping amount.</value>
		[DataMember]
		public decimal FreeOfShippingAmount { get; set; }

		/// <summary>
		/// Transporteur selectionné
		/// </summary>
		/// <value>The conveyor.</value>
		[DataMember]
		public Conveyor Conveyor { get; set; }

		/// <summary>
		/// Message associé au transport
		/// </summary>
		[DataMember]
		public string MessageForConveyor { get; set; }

		/// <summary>
		/// Accepte la conversion d'un devis en commande
		/// </summary>
		/// <value><c>true</c> if [accept conversion]; otherwise, <c>false</c>.</value>
		[DataMember]
		public bool? AcceptConversion { get; set; }

		/// <summary>
		/// Identifiant de la source de création d'un panier
		/// </summary>
		/// <value>From entity id.</value>
		[DataMember]
		public int? FromEntityId { get; set; }

		/// <summary>
		/// Numéro du type de source de création d'un panier
		/// </summary>
		/// <value>From meta entity id.</value>
		[DataMember]
		public int? FromMetaEntityId { get; set; }

		/// <summary>
		/// Nom de la validation, utilisé pour connaitre le contexte de validation
		/// </summary>
		/// <value>The name of the validation.</value>
		[DataMember]
		public string ValidationName { get; set; }

		/// <summary>
		/// Etat du panier
		/// </summary>
		[DataMember]
		public CartState State { get; set; }

	}
}